package com.iretailer.report.influxdb.service;

import com.iretailer.report.dto.CameraFlowModel;
import com.iretailer.report.influxdb.dao.InfluxdbDao;
import com.iretailer.report.influxdb.model.Passengerflow;
import com.iretailer.report.influxdb.util.TableName;
import com.iretailer.report.model.CameraZoneCamera;
import com.iretailer.report.model.PhysicalZoneMall;
import com.iretailer.report.util.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: xjw
 * @Date: 2019/1/23 16:25
 * @Description:
 */
@Service
public class InfluxdbFlowService {

    @Autowired
    private InfluxdbDao influxdbDao;

    /***
     * 用户前端查询客流
     * @param physicalZones
     * @param startTime
     * @param endTime
     * @param period
     * @return
     */
    public List<CameraFlowModel> getPhysicalZones_PeriodFlow(List<PhysicalZoneMall> physicalZones, String startTime, String endTime, String period) {
        List<CameraFlowModel> result = new ArrayList<>();
        if (physicalZones != null && physicalZones.size() > 0) {
            Map<String, List<PhysicalZoneMall>> timezonePZMap = physicalZones.stream().collect(Collectors.groupingBy(PhysicalZoneMall::getTimeZone));
            timezonePZMap.entrySet().forEach(it -> {
                String timezone = it.getKey();
                Map<Long, PhysicalZoneMall> pzmap = it.getValue().stream().collect(Collectors.toMap(PhysicalZoneMall::getId, a -> a));
                List<Passengerflow> flow = null;
                if (period.equals("7d")) {
                    flow = select_week(timezone, TableName.Passengerflow.Passengerflow_PZ, new ArrayList<>(pzmap.keySet()), startTime, endTime, "7d", "-3d");
                } else {
                    flow = selectFlow(timezone, TableName.Passengerflow.Passengerflow_PZ, new ArrayList<>(pzmap.keySet()), startTime, endTime, period);
                }
                if (flow != null && flow.size() > 0) {
                    for (Passengerflow pf : flow) {
                        PhysicalZoneMall pzm = pzmap.get(Long.valueOf(pf.getZoneid()));
                        CameraFlowModel cf = new CameraFlowModel();
                        cf.setMallCode(pzm.getMallCode());
                        cf.setPhysicalType(pzm.getZoneTypeName());
                        cf.setPhysicalZoneId(String.valueOf(pzm.getId()));
                        cf.setPhysicalZoneName(pzm.getName());
                        cf.setMallId(pzm.getMallId());
                        cf.setMallName(pzm.getMallName());
                        cf.setCityId(pzm.getCityId());
                        cf.setZonedDateTime(pf.getTime());
                        String time = TimeUtil.zoneDateTime_format(pf.getTime());
                        cf.setDateTime(time);
                        cf.setCountenter(pf.getCountEnter());
                        cf.setCountexit(pf.getCountExit());
                        result.add(cf);
                    }
                }
            });
        }
        return result;
    }

    /**
     * @Author xjw
     * @Date 2019/5/14 10:34
     * @Description :  用于汇总的
     **/
    public List<CameraFlowModel> getPhysicalZones_PeriodFlow(String timezone, List<PhysicalZoneMall> physicalZones, Set<Long> zoneIds, String startTime, String endTime, String period) {
        List<Passengerflow> flow = null;
        if (period.equals("7d")) {
            flow = select_week(timezone, TableName.Passengerflow.Passengerflow_B, new ArrayList<>(zoneIds), startTime, endTime, "7d", "-3d");
        } else {
            flow = selectFlow(timezone, TableName.Passengerflow.Passengerflow_B, new ArrayList<>(zoneIds), startTime, endTime, period);
        }
        Map<String, List<Passengerflow>> flowMap = new HashMap<>();
        if (flow != null) {
            flowMap = flow.stream().collect(Collectors.groupingBy(Passengerflow::getZoneid));
        }
        return getPhysicalZoneFlow(physicalZones, flowMap);
    }

    public List<Passengerflow> getZero(String timeZone, TableName.Passengerflow table, List<Long> zoneIds, String startTime, String endTime) {
        //客流置零
        List<Passengerflow> oldFlow = selectFlowGrid(timeZone, table, zoneIds, startTime, endTime);
        oldFlow.forEach(it -> {
            it.setCountEnter(0);
            it.setCountExit(0);
        });
        return oldFlow;
//        insertPassengerflow(oldFlow, table);
    }

    public List<Passengerflow> selectflowGroupByTime(String timeZone, TableName.Passengerflow table, List<Long> zoneIds, String startTime, String endTime, String groupBy) {
        return influxdbDao.selectflowGroupByTime(timeZone, table, zoneIds, startTime, endTime, groupBy);
    }

    public List<Passengerflow> selectFlowGrid(String timeZone, TableName.Passengerflow table, List<Long> zoneIds, String startTime, String endTime) {
        return influxdbDao.selectFlowGrid(timeZone, table, zoneIds, startTime, endTime);
    }

    public int upateFlow(String type, List<Passengerflow> flow) {
        int result = 0;
        switch (type) {
            case "All":
                result += insertPassengerflow(flow, TableName.Passengerflow.Passengerflow);
            default:
                //更新 营业时间的数据时，必须更新所有历史数据
                result += insertPassengerflow(flow, TableName.Passengerflow.Passengerflow);
                result += insertPassengerflow(flow, TableName.Passengerflow.Passengerflow_B);
        }
        return result;
    }

    public void copyFlowData(String sourceTimeZone, Long sourceZoneId, String startTime, String endTime, String targetTimeZone, Long targetZoneId, String targetDate) {
        List<Passengerflow> sourceData = selectFlow(sourceTimeZone, TableName.Passengerflow.Passengerflow_B, Arrays.asList(sourceZoneId), startTime, endTime, "1m");
        if (sourceData != null && sourceData.size() > 0) {
            sourceData.forEach(it -> {
                it.setZoneid(String.valueOf(targetZoneId));
                ZonedDateTime time = it.getTime();
                it.setTime(ZonedDateTime.of(TimeUtil.parse_LocalDate(targetDate), time.toLocalTime(), ZoneId.of(targetTimeZone)));
            });
            insertPassengerflow(sourceData, TableName.Passengerflow.Passengerflow_B);
            insertPassengerflow(sourceData, TableName.Passengerflow.Passengerflow);
        }
    }

    public List<Passengerflow> selectFlow(String timezone, String type, List<Long> zoneIds, String startTime, String endTime, String period) {
        switch (type) {
            case "All":
                switch (period) {
                    case "1m":
                        return influxdbDao.selectFlowGrid(timezone, TableName.Passengerflow.Passengerflow, zoneIds, startTime, endTime);
                    default:
                        return influxdbDao.selectflowGroupByZoneId(false, timezone, TableName.Passengerflow.Passengerflow, zoneIds, startTime, endTime, period);
                }
            default:
                switch (period) {
                    case "1m":
                        return influxdbDao.selectFlowGrid(timezone, TableName.Passengerflow.Passengerflow_B, zoneIds, startTime, endTime);
                    default:
                        return influxdbDao.selectflowGroupByZoneId(false, timezone, TableName.Passengerflow.Passengerflow_B, zoneIds, startTime, endTime, period);
                }

        }
    }

    public List<Passengerflow> selectFlow(String timezone, TableName.Passengerflow table, List<Long> zoneIds, String startTime, String endTime, String period) {
        return influxdbDao.selectflowGroupByZoneId(true, timezone, table, zoneIds, startTime, endTime, period);
    }

    public List<Passengerflow> select_week(String timezone, TableName.Passengerflow table, List<Long> zoneIds, String startTime, String endTime, String period, String offset) {
        return influxdbDao.selectflowGroup_offset_By_zoneid_Time(timezone, table, zoneIds, startTime, endTime, period, offset);
    }

    /**
     * @Author xjw
     * @Date 2019/1/28 12:00
     * @Description :  插入 客流 数据
     **/
    public int insertPassengerflow(List<Passengerflow> post, TableName.Passengerflow table) {
        int result = -1;
        int separateNumber = 50000;
        int size = post.size();
        if (size <= separateNumber) {
            result = influxdbDao.batchInsertPassengerflow(post, table);
        } else {
            int batchSize = size / separateNumber;
            int remain = size % separateNumber;
            for (int i = 0; i < batchSize; ) {
                int index = i * separateNumber;
                int toIndex = index + separateNumber;
                result += influxdbDao.batchInsertPassengerflow(post.subList(index, toIndex), table);
            }
            if (remain > 0) {
                result += influxdbDao.batchInsertPassengerflow(post.subList(size - remain, size), table);
            }

        }
        return result;
    }

    public List<CameraFlowModel> getPhysicalZoneFlow(List<PhysicalZoneMall> physicalZones, Map<String, List<Passengerflow>> flowMap) {

        Map<String, CameraFlowModel> resultMap = new HashMap<>();

        for (PhysicalZoneMall pz : physicalZones) {
            Long physicalZoneId = pz.getId();
            String physiacalZoneName = pz.getName();
            String mallId = pz.getMallId();
            String mallName = pz.getMallName();
            String cityId = pz.getCityId();
            for (CameraZoneCamera cz : pz.getCameraZones()) {
                String cameraZoneId = String.valueOf(cz.getId());
                int reverse = cz.getReverse();
                List<Passengerflow> flow = flowMap.get(cameraZoneId);
                if (flow != null) {
                    boolean reverseStatus = (reverse == 1);
                    for (Passengerflow pf : flow) {
                        String key = MessageFormat.format("{0}_{1}", physicalZoneId, pf.getTime());
                        CameraFlowModel find = resultMap.get(key);
                        if (find == null) {
                            CameraFlowModel cf = new CameraFlowModel();
                            cf.setPhysicalZoneId(String.valueOf(physicalZoneId));
                            cf.setPhysicalZoneName(physiacalZoneName);
                            cf.setMallId(mallId);
                            cf.setMallName(mallName);
                            cf.setCityId(cityId);
                            cf.setZonedDateTime(pf.getTime());
                            cf.setDateTime(TimeUtil.zoneDateTime_format(pf.getTime()));
                            enterExitReverSe(reverseStatus, cf, pf);
                            resultMap.put(key, cf);
                        } else {
                            enterExitReverSe(reverseStatus, find, pf);
                        }
                    }
                }

            }

        }
        return new ArrayList<>(resultMap.values());

    }

    private void enterExitReverSe(boolean status, CameraFlowModel cf, Passengerflow pf) {
        if (status) {
            cf.setCountenter(cf.getCountenter() + pf.getCountEnter());
            cf.setCountexit(cf.getCountexit() + pf.getCountExit());
        } else {
            cf.setCountenter(cf.getCountenter() + pf.getCountExit());
            cf.setCountexit(cf.getCountexit() + pf.getCountEnter());
        }
    }
}
